using Abp.Authorization;
using Abp.BackgroundJobs;
using Abp.Runtime.Caching;
using Abp.Runtime.Session;
using Abp.UI;
using Mt.Site.Application.Dto;
using Mt.Site.Application.Dto.Add;
using Mt.Site.Application.Navigation.Dto.MenuInfo;
using Mt.Site.Core.BackGroundJobs;
using Mt.Site.Core.BackGroundJobs.Navigations;
using Mt.Site.Core.Navigations;
using Mt.Site.Core.Navigations.Entities;
using Mt.Site.Core.Navigations.MenuInfo;
using Mt.Site.Core.Navigations.Permissions;
using Mt.Site.Core.Navigations.Values;
using Mt.Site.Core.Storage;
using Mt.Site.Core.Synchronization;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using MenuItemDto = Mt.Site.Core.Navigations.Values.MenuItemDto;

namespace Mt.Site.Application.Navigation
{
    public class MenuInfoAppService : MtSiteAppServiceBase, IMenuInfoAppService
    {
        private readonly IMenuInfoManager _menuInfoManager;

        private readonly IBackgroundJobManager _backgroundJobManager;
        private readonly IFileObjectManager _fileObjectManager;

        private readonly ICacheManager _cacheManager;

        public MenuInfoAppService(
            IMenuInfoManager menuInfoManager,
            IBackgroundJobManager backgroundJobManager,
            IFileObjectManager fileObjectManager,
            ICacheManager cacheManager)
        {
            _menuInfoManager = menuInfoManager;
            _backgroundJobManager = backgroundJobManager;

            _fileObjectManager = fileObjectManager;
            _cacheManager = cacheManager;
        }

        // TODO: 可以保留，提供一个集中维护的界面（有这种需求） ，待后面完善这个页面
        [AbpAuthorize(MenuPermissions.Pages_Tenant_MenusInfo_BatchManagment)]
        public async Task<List<MenuItemDto>> GetMenuTree(MenuIdDto input)
        {
            return await _menuInfoManager.GetMenuTree(input.MenuId);
        }

        [AbpAuthorize]
        public async Task<MenuDataConfigOutput> GetConfigForMenuData(MenuIdDto input)
        {
            var config = await _menuInfoManager.GetConfigForMenuData(input.MenuId);
            var menu = await _menuInfoManager.GetMenuItemByAuxiliaryId(input.MenuId);
            var menuId = menu.Id();
            var permissions = await _menuInfoManager.GetPermissionsAsync(menu.Id());
            return new MenuDataConfigOutput
            {
                Config = config,
                MenuId = menuId,
                Permissions = permissions,
                DisplayName = menu.DisplayName()
            };
        }

        #region 图文


        [AbpAuthorize(MenuPermissions.Pages_Tenant_MenusInfo_ImageText, MenuPermissions.Pages_Tenant_MenusInfo_ExtendedData, RequireAllPermissions = false)]
        public async Task<Dictionary<string, List<Dictionary<string, object>>>> GetAllImageTextAsync(MenuIdAndGuidInput input)
        {
            if (input.MenuGuid.HasValue)
            {
                return await _menuInfoManager.GetDatasAsync(input.MenuId, input.MenuGuid.Value);
            }

            var menu = await _menuInfoManager.GetMenuItemByAuxiliaryId(input.MenuId);
            var menuId = menu.Id();
            return await _menuInfoManager.GetDatasAsync(input.MenuId, menuId);
        }

        [AbpAuthorize(MenuPermissions.Pages_Tenant_MenusInfo_ImageText)]
        public async Task<Dictionary<string, object>> GetListDataForEditAsync(GetImageTextForEditInput input)
        {
            if (input.MenuGuid.HasValue)
            {
                return await _menuInfoManager.GetListDataForEditAsync(input.Id, input.MenuId, input.MenuGuid.Value, input.DataKey);
            }

            var menu = await _menuInfoManager.GetMenuItemByAuxiliaryId(input.MenuId);
            var menuId = menu.Id();
            return await _menuInfoManager.GetListDataForEditAsync(input.Id, input.MenuId, menuId, input.DataKey);
        }

        [AbpAuthorize(MenuPermissions.Pages_Tenant_MenusInfo_ImageText)]
        public async Task<List<Dictionary<string, object>>> GetListDataAsync(GetImageTextListInput input)
        {
            if (input.MenuGuid.HasValue)
            {
                return await _menuInfoManager.GetListDatasAsync(input.MenuId, input.MenuGuid.Value, input.DataKey);
            }

            var menu = await _menuInfoManager.GetMenuItemByAuxiliaryId(input.MenuId);
            var menuId = menu.Id();
            return await _menuInfoManager.GetListDatasAsync(input.MenuId, menuId, input.DataKey);
        }

        [AbpAuthorize(MenuPermissions.Pages_Tenant_MenusInfo_ExtendedData)]
        public async Task<Dictionary<string, object>> GetSingleDataForEditAsync(GetImageTextForEditInput input)
        {
            if (input.MenuGuid.HasValue)
            {
                return await _menuInfoManager.GetSingleDataForEditAsync(input.MenuId, input.MenuGuid.Value, input.DataKey);
            }

            var menu = await _menuInfoManager.GetMenuItemByAuxiliaryId(input.MenuId);
            var menuId = menu.Id();
            return await _menuInfoManager.GetSingleDataForEditAsync(input.MenuId, menuId, input.DataKey);
        }

        [AbpAuthorize(MenuPermissions.Pages_Tenant_MenusInfo_ExtendedData_Edit)]
        public async Task<Guid> CreateOrUpdateExtendedData(CreateOrUpdateImageTextInput input)
        {
            Guid id;
            if (input.Id.HasValue)
            {
                id = input.Id.Value;
                await _menuInfoManager.UpdateAsync(input.Values, id, input.MenuId, MenuExtendedData.Key);
                SyncImageText(input.MenuId, id, OptionType.Update);
            }
            else
            {
                id = await _menuInfoManager.CreateAsync(input.Values, input.MenuId, MenuExtendedData.Key);
                SyncImageText(input.MenuId, id, OptionType.Create);

                if (input.RandomId.HasValue)
                {
                    await _fileObjectManager.BuildRelationships(id, input.RandomId.Value);
                }
            }
            return id;
        }

        [AbpAuthorize(MenuPermissions.Pages_Tenant_MenusInfo_ImageText_Create)]
        public async Task<Guid> CreateOrUpdateImageTextAsync(CreateOrUpdateImageTextInput input)
        {
            Guid id;
            if (input.Id.HasValue)
            {
                id = input.Id.Value;
                await _menuInfoManager.UpdateAsync(input.Values, id, input.MenuId, input.DataKey);
                SyncImageText(input.MenuId, id, OptionType.Update);
            }
            else
            {
                id = await _menuInfoManager.CreateAsync(input.Values, input.MenuId, input.DataKey);
                SyncImageText(input.MenuId, id, OptionType.Create);

                if (input.RandomId.HasValue)
                {
                    await _fileObjectManager.BuildRelationships(id, input.RandomId.Value);
                }
            }
            return id;
        }

        [AbpAuthorize(MenuPermissions.Pages_Tenant_MenusInfo_ImageText_Delete)]
        public async Task DeleteImageTextAsync(MenuAndIdInput<Guid> input)
        {
            var menuId = await _menuInfoManager.GetMenuIdForEntity(input.Id);

            await _menuInfoManager.DeleteAysnc(input.Id);

            SyncImageText(menuId, input.Id, OptionType.Delete);
        }

        [AbpAuthorize(MenuPermissions.Pages_Tenant_MenusInfo_ImageText_Edit)]
        public async Task SetImageTextStatus(SetStatusWithMenuIdInput input)
        {
            if (input.IdList.Count == 0)
            {
                return;
            }

            var menuFid = await _menuInfoManager.GetMenuIdForEntity(input.IdList[0]);

            await _menuInfoManager.SetStatus(input.IdList, input.IsActive);

            foreach (var item in input.IdList)
            {
                SyncImageText(menuFid, item, OptionType.Update);
            }
        }

        [AbpAuthorize(MenuPermissions.Pages_Tenant_MenusInfo_ImageText_Edit)]
        public async Task SwapImageTextSortNumber(SwapSortNumberWithMenuIdInput input)
        {
            var idList = input.IdOrderList.Select(c => c.Id).ToList();
            var orderList = input.IdOrderList.Select(c => c.Order).ToList();

            if (idList.Count == 0)
            {
                return;
            }

            await _menuInfoManager.SwapObjectSortAsync(idList, orderList);

            var menuFid = await _menuInfoManager.GetMenuIdForEntity(idList[0]);

            foreach (var item in idList)
            {
                SyncImageText(menuFid, item, OptionType.Update);
            }
        }

        [AbpAuthorize(MenuPermissions.Pages_Tenant_MenusInfo_ImageText_Edit)]
        public async Task SetNewSorNumberForImageText(NewSortNumberWithMenuIdInput input)
        {
            await _menuInfoManager.SetNewOrderNumberAsync(input.Id, input.NewNumber);

            var menuFid = await _menuInfoManager.GetMenuIdForEntity(input.Id);

            SyncImageText(menuFid, input.Id, OptionType.Update);
        }
        #endregion


        #region 编辑配置数据

        /*
 栏目上关联的配置数据提供了三种

 栏目配置管理中使用配置信息，涉及表单配置，需超管权限来维护
 public const string Config = "MenuInfo";               

 自定义的配置信息，内容可能比较敏感，需超管权限来维护
 public const string CustomedConfig = "CustomedConfig";

 用于为某栏目配置一些特殊数据，可能会分配给普通管理员维护
 public const string CustomedData = "CustomedData";  
 */


        [AbpAuthorize(MenuPermissions.Pages_Tenant_MenusInfo_Config)]
        public async Task<MenuConfigOutput> GetConfigAsync(MenuIdDto input)
        {
            var config = await _menuInfoManager.GetConfig(input.MenuId, MenuInfoManager.Config);
            if (config == null)
            {
                config = GetDefaultMenuConfig();
            }

            return new MenuConfigOutput
            {
                ExtensionData = config.ExtensionData,
                AutoSynchronous = config.AutoSynchronous
            };
        }

        private MenuConfig GetDefaultMenuConfig()
        {
            var data = @"{
	""imageText"":{
		""enable"":false
	},
	""extendedData"":{
		""enable"":false
	}	
}";
            return new MenuConfig
            {
                ExtensionData = data
            };
        }


        [AbpAuthorize(MenuPermissions.Pages_Tenant_MenusInfo_Config)]
        public async Task<MenuConfigOutput> GetCustomConfigAsync(MenuIdDto input)
        {
            var config = await _menuInfoManager.GetConfig(input.MenuId, MenuInfoManager.CustomedConfig);
            if (config == null)
            {
                return null;
            }
            return new MenuConfigOutput
            {
                ExtensionData = config.ExtensionData,
                AutoSynchronous = config.AutoSynchronous
            };
        }

        [AbpAuthorize(MenuPermissions.Pages_Tenant_MenusInfo_CustomData)]
        public async Task<MenuConfigOutput> GetCustomDataAsync(MenuIdDto input)
        {
            var config = await _menuInfoManager.GetConfig(input.MenuId, MenuInfoManager.CustomedData);
            if (config == null)
            {
                return null;
            }
            return new MenuConfigOutput
            {
                ExtensionData = config.ExtensionData,
                AutoSynchronous = config.AutoSynchronous
            };
        }


        [AbpAuthorize(MenuPermissions.Pages_Tenant_MenusInfo_Config_Edit)]
        public async Task SetConfigAsync(SetMenuConfigInput input)
        {
            var id = await _menuInfoManager.CreatOrUpdateConfig(input.MenuId, input.ExtensionData, input.AutoSynchronous
                , MenuInfoManager.Config);

            SyncMenuConfig(input.MenuId, id, OptionType.Update);
        }

        [AbpAuthorize(MenuPermissions.Pages_Tenant_MenusInfo_Config_Edit)]
        public async Task SetCustomConfigAsync(SetMenuConfigInput input)
        {
            var id = await _menuInfoManager.CreatOrUpdateConfig(input.MenuId, input.ExtensionData, input.AutoSynchronous
                , MenuInfoManager.CustomedConfig);

            SyncMenuConfig(input.MenuId, id, OptionType.Update);
        }


        [AbpAuthorize(MenuPermissions.Pages_Tenant_MenusInfo_CustomData_Edit)]
        public async Task SetCustomDataAsync(SetMenuConfigInput input)
        {
            var id = await _menuInfoManager.CreatOrUpdateConfig(input.MenuId, input.ExtensionData, input.AutoSynchronous
                , MenuInfoManager.CustomedData);

            SyncMenuConfig(input.MenuId, id, OptionType.Update);
        }

        #endregion

        private void SyncMenuConfig(long menuId, Guid id, OptionType optionType)
        {
            if (MtSiteConsts2.BackgroundJobs && menuId > 0)
            {
                _backgroundJobManager.Enqueue<SynchorizationMenuConfigJob, BaseAndMenuIdArgs>(
                new BaseAndMenuIdArgs
                {
                    FromLanguage = AbpSession.CultureName(),
                    Id = id,
                    FromTenantId = AbpSession.GetTenantId(),
                    MenuId = menuId,
                    OperateType = optionType
                });
            }
        }

        private void SyncImageText(long menuFid, Guid dataId, OptionType optionType)
        {
            if (MtSiteConsts2.BackgroundJobs && menuFid > 0)
            {
                _backgroundJobManager.Enqueue<SynchorizationImgTextJob, BaseAndMenuIdArgs>(
                new BaseAndMenuIdArgs
                {
                    FromLanguage = AbpSession.CultureName(),
                    Id = dataId,
                    FromTenantId = AbpSession.GetTenantId(),
                    MenuId = menuFid,
                    OperateType = optionType
                });
            }

            _cacheManager.GetCache<long, List<MenuExtendedData>>(ApiCacheNames.MenuInfoCache).Remove(menuFid);
        }
    }
}
